import cn.hutool.core.collection.CollUtil;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.DoubleSummaryStatistics;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 买入卖出比例策略
 * @author 吴宇亮 on 2023/8/25 9:21
 */
public class RateStrategy {

    public static void main(String[] args) {
        RateStrategy rateStrategy = new RateStrategy();

        double firstMoeny, grouthRate;
        List<Double> growth;

//        firstMoeny = 1, grouthRate = 2;
//        System.out.println("初始投入" + firstMoeny + "%的钱，每次增长" + grouthRate + "倍");
//        growth = rateStrategy.growth(firstMoeny, grouthRate);
//        System.out.println("总定投次数：" + growth.size());
//        System.out.println(CollUtil.join(growth, ", "));
//        System.out.println();
//
        firstMoeny = 5;
        grouthRate = 1.5;
        System.out.println("初始投入" + firstMoeny + "%的钱，每次增长" + grouthRate + "倍");
        growth = rateStrategy.growth(firstMoeny, grouthRate);
        System.out.println("总定投次数：" + growth.size());
        System.out.println(CollUtil.join(growth, ", "));
        System.out.println();

//        firstMoeny = 10;
//        grouthRate = 1.05;
//        System.out.println("初始投入" + firstMoeny + "%的钱，每次增长" + grouthRate + "倍");
//        growth = rateStrategy.growth(firstMoeny, grouthRate);
//        System.out.println("总定投次数：" + growth.size());
//        System.out.println(CollUtil.join(growth, ", "));
    }

    /**
     * 收益 = 数学期望为正的模型 + 无限子弹 <br/>
     * 计算出子弹次数，从而得到相对的“无限子弹”。 <br/> <br/>
     *
     * growthRate增长率越小，风险相对越低，因为定投的次数会变多 <br/>
     * 但收益变大还是变小取决于行情反转的速度，如果认为行情反转速度较快，则增长率应该加大，减少定投次数；反之增长率应该减小<br/>
     *
     * 假设总共有100块钱，也就是100%的仓位
     * @param firstMoney 第一次买入/卖出的钱，区间范围 [1, 100]
     * @param growthRate 增长率，区间范围 [1, ]。
     */
    private List<Double> growth(double firstMoney, double growthRate) {
        if (firstMoney >= 100) {
            throw new IllegalArgumentException("初次买入/卖出的资金比例不可能超过100%");
        }
        if (growthRate < 1) {
            throw new IllegalArgumentException("应该越便宜买的越多，所以growthRate应该大于1");
        }
        List<Double> rateList = new ArrayList<>();
        rateList.add(firstMoney);
        // 增长
        this.growth(rateList, growthRate);
        return rateList;
    }

    /**
     * 资金增长
     */
    private void growth(List<Double> rateList, double growthRate) {
        Double initMoney = rateList.get(rateList.size() - 1);
        DoubleSummaryStatistics statistics = rateList.stream().collect(Collectors.summarizingDouble(item -> item));
        // 假设增长
        double growthMoney = BigDecimal.valueOf(initMoney).multiply(BigDecimal.valueOf(growthRate)).doubleValue();
        // 假设增长后的总的钱还没超过100，还可以增长
        double sum = statistics.getSum();
        if (sum + growthMoney <= 100) {
            // 实际增长
            rateList.add(growthMoney);
            // 递归
            this.growth(rateList, growthRate);
        }
        // 假设增长后超过100%，取消增长
        else {
            // 剩余
            double remaining = BigDecimal.valueOf(100).subtract(BigDecimal.valueOf(sum)).doubleValue();
            rateList.add(remaining);
            // 递归出口
            return;
        }
    }
}
